package Leetcode.每日一题;

import java.util.HashSet;

/**
 * @ClassName 模拟行走机器人
 * @since: 2023/7/19 22:01
 * @auth: kirito
 * @description:
 * 机器人在一个无限大小的 XY 网格平面上行走，从点 (0, 0) 处开始出发，面向北方。该机器人可以接收以下三种类型的命令 commands ：
 *
 * -2 ：向左转 90 度
 * -1 ：向右转 90 度
 * 1 <= x <= 9 ：向前移动 x 个单位长度
 * 在网格上有一些格子被视为障碍物 obstacles 。第 i 个障碍物位于网格点  obstacles[i] = (xi, yi) 。
 *
 * 机器人无法走到障碍物上，它将会停留在障碍物的前一个网格方块上，但仍然可以继续尝试进行该路线的其余部分。
 *
 * 返回从原点到机器人所有经过的路径点（坐标为整数）的最大欧式距离的平方。（即，如果距离为 5 ，则返回 25 ）
 *
 * 简述一下做题思路，首先判断数字与0关系
 * 》0  往当前方向走 n步  判断x+ 或者y+ 是否在障碍物上
 * 《0  -1 右转
 *      -2 左转
 *      难点就卡在这个方向上，想不到用什么来表示方向，解析很神奇，定义了一个二维数组表示方向，详情看官网
 *      https://leetcode.cn/problems/walking-robot-simulation/
 *      然后通过 取余操作判断方向  设定方向后再在》0的方向走 n 同时判断障碍
 *
 *      下面的方法相当于new了一个二维坐标防止障碍点  方便判断
 *      这个实现应该不难 主要是用一个二维数组表示方向想不太出
 *      最开始自己用最笨的办法，枚举，四个方向，三个转向，3*4种方式 左 右 不转  然后走  太笨了不想实现，
 *      实现的话有一丢丢难度但是不大
 **/
public class 模拟行走机器人 {
    static int[][] dirs = {{0, 1}, {1, 0}, {0, -1}, {-1, 0}};

    public int robotSim(int[] commands, int[][] obstacles) {

        HashSet<Point> obstaclesSet = new HashSet<>();

        for (int[] o : obstacles) {
            obstaclesSet.add(new Point(o[0], o[1]));
        }

        int x = 0, y = 0, maxDistance = 0, heading = 0;
        for (int command : commands) {
            if (command < 0) {

                if (command == -2)
                    heading = (heading + 3) % 4;
                else
                    heading = (heading + 1) % 4;
            } else {

                int dx = dirs[heading][0];
                int dy = dirs[heading][1];
                while(command-- > 0) {
                    x += dx;
                    y += dy;
                    if (isPathBlocked(x,y, obstaclesSet)) {
                        x -= dx;
                        y -= dy;
                        break;
                    }
                }
                maxDistance = Math.max( x * x + y * y, maxDistance);
            }
        }
        return maxDistance;
    }

    private static boolean isPathBlocked(int x, int y, HashSet<Point> obstacles) {
        return obstacles.contains(new Point(x, y));
    }

    private static class Point{
        int x;
        int y;

        public Point(int x, int y) {
            this.x = x;
            this.y = y;
        }

        @Override
        public boolean equals(Object o) {
            if (this == o) return true;
            if (o == null || getClass() != o.getClass()) return false;

            Point point = (Point) o;

            if (x != point.x) return false;
            return y == point.y;
        }

        @Override
        public int hashCode() {
            int result = x;
            result = 31 * result + y;
            return result;
        }
    }
}
